import Vue from 'vue'

Object.assign(Vue.prototype, {

  // 注入插槽
  // - @slot 插槽名
  // - @id 注入ID（相同ID的注入将被替换而非新增，但一前一后则可共存）
  // - @nodes 要注入的虚拟节点列表（null表示删除该注入），亦可为一个返回虚拟节点列表的函数（参数为注入前的虚拟节点列表），表示整体替换
  // - @before 是否加到最前面（否则加到最后面），替换时位置不变（当nodes为函数时忽略此参数）
  $injectSlot(slot, id, nodes, before = false) {
    const injection = { id, nodes }
    const f = this.$scopedSlots[slot]
    if (f && f.__origSlot) {
      let side
      if (nodes instanceof Function) {
        side = f.__injectSwap
        before = false
      } else if (before) {
        side = f.__injectBefore
      } else {
        side = f.__injectAfter
      }
      const index = side.findIndex(item => item.id === id)
      if (index < 0) {
        if (nodes == null) return
        if (before) {
          side.unshift(injection)
        } else {
          side.push(injection)
        }
      } else {
        if (nodes == null) {
          side.splice(index, 1)
        } else {
          side[index] = injection
        }
      }
    } else {
      if (nodes == null) return
      const injected = props => {
        const nodes = [
          injected.__injectBefore.flatMap(item => item.nodes || []),
          (injected.__origSlot && injected.__origSlot(props)) || [],
          injected.__injectAfter.flatMap(item => item.nodes || [])
        ]
        return injected.__injectSwap.reduce((all, item) => {
          return item.nodes(all) || []
        }, nodes.flat())
      }
      injected.__origSlot = f
      injected.__injectBefore = []
      injected.__injectAfter = []
      injected.__injectSwap = []
      if (nodes instanceof Function) {
        injected.__injectSwap.push(injection)
      } else if (before) {
        injected.__injectBefore.push(injection)
      } else {
        injected.__injectAfter.push(injection)
      }
      this.$scopedSlots[slot] = injected
    }
  }
})
